/*jshint smarttabs:true, eqeqeq:false, eqnull:true, laxbreak:true*/

(function(window, document, jqLite, undefined) {
	// To allow non strict code to be concatenated together with vx into a single file
	'use strict';
	////////////////////////////////////
	// private Utility
	///////////////////////////////////

	/**
	 * @vxdoc function
	 * @name vx.lowercase
	 * @function
	 *
	 * @description Converts the specified string to lowercase.
	 * @param {string} string String to be converted to lowercase.
	 * @returns {string} Lowercased string.
	 */
	var lowercase = function(string) {
		return isString(string) ? string.toLowerCase() : string;
	};

	/**
	 * @vxdoc function
	 * @name vx.uppercase
	 * @function
	 *
	 * @description Converts the specified string to uppercase.
	 * @param {string} string String to be converted to uppercase.
	 * @returns {string} Uppercased string.
	 */
	var uppercase = function(string) {
		return isString(string) ? string.toUpperCase() : string;
	};

	// String#toLowerCase and String#toUpperCase don't produce correct results in browsers with Turkish
	// locale, for this reason we need to detect this case and redefine lowercase/uppercase methods
	// with correct but slower alternatives.
	if ('i' !== 'I'.toLowerCase()) {
		lowercase = function(s) {
			return isString(s) ? s.replace(/[A-Z]/g, function(ch) {
				return String.fromCharCode(ch.charCodeAt(0) | 32);
			}) : s;
		};
		uppercase = function(s) {
			return isString(s) ? s.replace(/[a-z]/g, function(ch) {
				return String.fromCharCode(ch.charCodeAt(0) & ~32);
			}) : s;
		};
	}

	var/*Error = window.Error, */ _slice = [].slice, _toString = Object.prototype.toString, _nodeName, // aliases
	msie = int((/msie (\d+)/.exec(lowercase(window.navigator.userAgent)) || [])[1]), escape = window.escape, unescape = window.unescape,
	// major version number for IE or NaN for others
	hashId = ['0', '0', '0'], scopeId = ['0', '0', '0'], inputId = ['0', '0', '0'], VID = ['0', '0', '0', '0', '0', '0'];

	if ( typeof document.getAttribute == 'undefined')
		document.getAttribute = function() {
		};

	if (msie < 9) {
		_nodeName = function(element) {
			element = element.nodeName ? element : element[0];
			return (element.scopeName && element.scopeName != 'HTML') ? //
			uppercase(element.scopeName + ':' + element.nodeName) : element.nodeName;
		};
	} else {
		_nodeName = function(element) {
			return element.nodeName ? element.nodeName : element[0].nodeName;
		};
	}

	/**
	 * @description
	 *
	 * This object extends the error class and provides interpolation capability
	 * to make it easier to write and read Error messages within vx. It can
	 * be called as follows:
	 *
	 * throw vError(13, 'This {0} is {1}', foo, bar);
	 *
	 * The above will replace {0} with the value of foo, and {1} with the value of
	 * bar. The object is not restricted in the number of arguments it can take.
	 *
	 * If fewer arguments are specified than necessary for interpolation, the extra
	 * interpolation markers will be preserved in the final string.
	 *
	 * @param {...} arguments The first argument to this object is the error
	 *     number, the second argument the message with templated points for
	 *     Interpolation (of the for {0} for the first, {1} for the second and
	 *     so on). The second argument onwards are interpolated into the error
	 *     message string in order.
	 */
	function vError() {
		var message = '[VX_ERR_' + arguments[0] + '] ' + arguments[1], i = 0, l = arguments.length - 2, curlyRegexp, arg;

		for (; i < l; i++) {
			curlyRegexp = new RegExp("\\{" + i + "\\}", "gm");
			arg = arguments[i + 2];

			if (isFunction(arg)) {
				arg = arg.toString().replace(/ \{[\s\S]*$/, '');
			} else if (!isString(arg)) {
				arg = toJson(arg);
			}

			message = message.replace(curlyRegexp, arg);
		}

		// even if we are called as constructor we can bypass the new vError instance and return
		// an instance of a real Error that contains correct stack info + extra frame for vError call
		// TODO(i): can we rewrite the stack string to remove vError frame?
		return new Error(message);
	}

	function int(str) {
		return parseInt(str, 10);
	}

	function cleanupClosure(obj) {
		for (var i in obj) {
			if (!obj.hasOwnProperty(i))
				continue;
			if (isFunction(obj[i])) {
				obj[i] = noop;
			} else {
				obj[i] = undefined;
			}
		}
	}

	function repaintFactory(el) {
		return function() {
			// now just find IE8 does not render after $digest, so change body's class, let do it.
			// IE9 radio also not render
			if (msie/* === 8*/) {
				repaint(el);
			}
		};
	}

	function repaint(el) {
		var clazz = 'vx-repaint-fix';
		el.addClass(clazz);
		window.setTimeout(function() {
			el.removeClass(clazz);
		}, 1);
	}

	function now() {
		return new Date().getTime();
	}

	/**
	 * when using forEach the params are value, key, but it is often useful to have key, value.
	 * @param {function(string, *)} iteratorFn
	 * @returns {function(*, string)}
	 */
	function reverseParams(iteratorFn) {
		return function(value, key) {
			iteratorFn(key, value);
		};
	}

	function supportObject(delegate) {
		return function(key, value) {
			if (isObject(key)) {
				forEach(key, reverseParams(delegate));
			} else {
				return delegate(key, value);
			}
		};
	}

	/**
	 * A consistent way of creating unique IDs in vx. The ID is a sequence of alpha numeric
	 * characters such as '012ABC'. The reason why we are not using simply a number counter is that
	 * the number string gets longer over time, and it can also overflow, where as the the nextId
	 * will grow much slower, it is a string, and it will never overflow.
	 *
	 * @returns an unique alpha-numeric string
	 */
	function nextUid(uid) {
		var index = uid.length;
		var digit;

		while (index) {
			index--;
			digit = uid[index].charCodeAt(0);
			if (digit == 57 /*'9'*/) {
				uid[index] = 'A';
				return uid.join('');
			}
			if (digit == 90 /*'Z'*/) {
				uid[index] = '0';
			} else {
				uid[index] = String.fromCharCode(digit + 1);
				return uid.join('');
			}
		}
		uid.unshift('1');
		//overflow and then prepend 1 bit as 1
		return uid.join('');
	}

	/**
	 * Set or clear the hashkey for an object.
	 * @param obj object
	 * @param h the hashkey (!truthy to delete the hashkey)
	 */
	function setHashKey(obj, h) {
		if (h) {
			obj.$$hashKey = h;
		} else {
			delete obj.$$hashKey;
		}
	}

	// Generates a random UUID
	function uuid() {
		// Logic borrowed from http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
		return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
			var r = Math.random() * 16 | 0, v = c === "x" ? r : (r & 0x3 | 0x8);
			return v.toString(16);
		});
	}

	function map(obj, iterator, context) {
		var results = [];
		forEach(obj, function(value, index, list) {
			results.push(iterator.call(context, value, index, list));
		});
		return results;
	}

	function sortedKeys(obj) {
		var keys = [];
		for (var key in obj) {
			if (obj.hasOwnProperty(key)) {
				keys.push(key);
			}
		}
		return keys.sort();
	}

	function forEachSorted(obj, iterator, context) {
		var keys = sortedKeys(obj);
		for (var i = 0, len = keys.length; i < len; i++) {
			iterator.call(context, obj[keys[i]], keys[i]);
		}
		return keys;
	}

	/**
	 * @description
	 * Determines the number of elements in an array, the number of properties an object has, or
	 * the length of a string.
	 *
	 * Note: This function is used to augment the Object type in VX expressions. See
	 * {@link vx.Object} for more information about VX arrays.
	 *
	 * @param {Object|Array|string} obj Object, array, or string to inspect.
	 * @param {boolean} [ownPropsOnly=false] Count only "own" properties in an object
	 * @returns {number} The size of `obj` or `0` if `obj` is neither an object nor an array.
	 */
	function size(obj, ownPropsOnly) {
		var _size = 0, key;
		if (isArray(obj) || isString(obj)) {
			return obj.length;
		} else if (isObject(obj)) {
			for (key in obj)
			if (!ownPropsOnly || obj.hasOwnProperty(key))
				_size++;
		}
		return _size;
	}

	function arrayRemove(array, value) {
		var index = indexOf(array, value);
		if (index >= 0)
			array.splice(index, 1);
		return value;
	}

	function sliceArgs(args, startIndex) {
		return _slice.call(args, startIndex || 0);
	}

	function _fastInvoke(fnPtr, context, args) {
		// Performance optimization: http://jsperf.com/apply-vs-call-vs-invoke
		switch (context && fnPtr.apply ? -1 : args.length) {
			case  0:
				return fnPtr();
			case  1:
				return fnPtr(args[0]);
			case  2:
				return fnPtr(args[0], args[1]);
			case  3:
				return fnPtr(args[0], args[1], args[2]);
			case  4:
				return fnPtr(args[0], args[1], args[2], args[3]);
			case  5:
				return fnPtr(args[0], args[1], args[2], args[3], args[4]);
			case  6:
				return fnPtr(args[0], args[1], args[2], args[3], args[4], args[5]);
			case  7:
				return fnPtr(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
			case  8:
				return fnPtr(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7]);
			case  9:
				return fnPtr(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8]);
			case 10:
				return fnPtr(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9]);
			default:
				return fnPtr.apply(context, args);
		}
	}

	/**
	 * @returns {string} Returns the string representation of the element.
	 */
	function startingTag(element) {
		element = jqLite(element).clone();
		try {
			// turns out IE does not let you set .html() on elements which
			// are not allowed to have children. So we just ignore it.
			element.html('');
		} catch(e) {
		}
		// As Per DOM Standards
		var TEXT_NODE = 3;
		var elemHtml = jqLite('<div>').append(element).html();
		try {
			return element[0].nodeType === TEXT_NODE ? lowercase(elemHtml) : elemHtml.
			match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/, function(match, nodeName) {
				return '<' + lowercase(nodeName);
			});
		} catch(e) {
			return lowercase(elemHtml);
		}
	}

	var SNAKE_CASE_REGEXP = /[A-Z]/g;
	function snake_case(name, separator) {
		separator = separator || '_';
		return name.replace(SNAKE_CASE_REGEXP, function(letter, pos) {
			return ( pos ? separator : '') + letter.toLowerCase();
		});
	}

	/**
	 * Converts snake_case to camelCase.
	 * Also there is special case for Moz prefix starting with upper case letter.
	 * @param name Name to normalize
	 */
	var SPECIAL_CHARS_REGEXP = /([\:\-\_]+(.))/g;
	var MOZ_HACK_REGEXP = /^moz([A-Z])/;
	function camelCase(name) {
		return name.replace(SPECIAL_CHARS_REGEXP, function(_, separator, letter, offset) {
			return offset ? letter.toUpperCase() : letter;
		}).replace(MOZ_HACK_REGEXP, 'Moz$1');
	}

	/**
	 * throw error if the argument is falsy.
	 */
	function assertArg(arg, name, reason) {
		if (!arg) {
			throw vError(1, "Argument '{0}' is {1}", (name || '?'), (reason || "required"));
		}
		return arg;
	}

	function assertArgFn(arg, name, acceptArrayAnnotation) {
		if (acceptArrayAnnotation && isArray(arg)) {
			arg = arg[arg.length - 1];
		}
		assertArg(isFunction(arg), name, 'not a function, got ' + (arg && typeof arg == 'object' ? arg.constructor.name || 'Object' : typeof arg));
		return arg;
	}

	function padNumber(num, digits, trim) {
		var neg = '';
		if (num < 0) {
			neg = '-';
			num = -num;
		}
		num = '' + num;
		while (num.length < digits)
		num = '0' + num;
		if (trim)
			num = num.substr(num.length - digits);
		return neg + num;
	}

	/**
	 * Computes a hash of an 'obj'.
	 * Hash of a:
	 *  string is string
	 *  number is number as string
	 *  object is either result of calling $$hashKey function on the object or uniquely generated id,
	 *         that is also assigned to the $$hashKey property of the object.
	 *
	 * @param obj
	 * @returns {string} hash string such that the same input will have the same hash string.
	 *         The resulting string key is in 'type:hashKey' format.
	 */
	function hashKey(obj) {
		var objType = typeof obj, key;
		if (objType == 'object' && obj !== null) {
			if ( typeof ( key = obj.$$hashKey) == 'function') {
				// must invoke on object to keep the right this
				key = obj.$$hashKey();
			} else if (key === undefined) {
				key = obj.$$hashKey = nextUid(hashId);
			}
		} else {
			key = obj;
		}
		return objType + ':' + key;
	}

	/**
	 * HashMap which can use objects as keys
	 */
	function HashMap(array) {
		forEach(array, this.put, this);
	}


	HashMap.prototype = {
		/**
		 * Store key value pair
		 * @param key key to store can be any type
		 * @param value value to store can be any type
		 */
		put : function(key, value) {
			this[hashKey(key)] = value;
		},
		/**
		 * @param key
		 * @returns the value for the key
		 */
		get : function(key) {
			return this[hashKey(key)];
		},
		/**
		 * Remove the key/value pair
		 * @param key
		 */
		remove : function(key) {
			var value = this[ key = hashKey(key)];
			delete this[key];
			return value;
		}
	};

	////////////////////////////////////
	// public Utility
	///////////////////////////////////
	// vx handle
	var vx = window.vx || (window.vx = {});

	function define(name, obj) {
		var part, c = window, parts;
		if (name.length > 0) {
			parts = name.split(".");
			for (var i = 0, ii = parts.length; i < ii; i++) {
				part = parts[i];
				c = c[part] || (c[part] = {});
			}
		}
		var a = [];
		for (var e in obj) {
			if (obj.hasOwnProperty(e))
				a.push(c[e] = obj[e]);
		}
		return a;
	}

	/**
	 * @private
	 * @param {*} obj
	 * @return {boolean} Returns true if `obj` is an array or array-like object (NodeList, Arguments, ...)
	 */
	function isArrayLike(obj) {
		if (!obj || ( typeof obj.length !== 'number'))
			return false;

		// We have on object which has length property. Should we treat it as array?
		if ( typeof obj.hasOwnProperty != 'function' && typeof obj.constructor != 'function') {
			// This is here for IE8: it is a bogus object treat it as array;
			return true;
		} else {
			return obj instanceof jqLite || // JQLite
			_toString.call(obj) !== '[object Object]' || // some browser native object
			typeof obj.callee === 'function';
			// arguments (on IE8 looks like regular obj)
		}
	}

	/**
	 * @vxdoc function
	 * @name vx.forEach
	 * @function
	 *
	 * @description
	 * Invokes the `iterator` function once for each item in `obj` collection, which can be either an
	 * object or an array. The `iterator` function is invoked with `iterator(value, key)`, where `value`
	 * is the value of an object property or an array element and `key` is the object property key or
	 * array element index. Specifying a `context` for the function is optional.
	 *
	 * Note: this function was previously known as `vx.foreach`.
	 *
	 <pre>
	 var values = {name: 'misko', gender: 'male'};
	 var log = [];
	 vx.forEach(values, function(value, key){
	 this.push(key + ': ' + value);
	 }, log);
	 expect(log).toEqual(['name: misko', 'gender:male']);
	 </pre>
	 *
	 * @param {Object|Array} obj Object to iterate over.
	 * @param {Function} iterator Iterator function.
	 * @param {Object=} context Object to become context (`this`) for the iterator function.
	 * @returns {Object|Array} Reference to `obj`.
	 */

	function forEach(obj, iterator, context) {
		var key, len;
		if (obj) {
			if (isFunction(obj)) {
				for (key in obj) {
					if (key != 'prototype' && key != 'length' && key != 'name' && obj.hasOwnProperty(key)) {
						iterator.call(context, obj[key], key);
					}
				}
			} else if (obj.forEach && obj.forEach !== forEach) {
				obj.forEach(iterator, context);
			} else if (isArrayLike(obj)) {
				for ( key = 0, len = obj.length; key < len; key++)
					iterator.call(context, obj[key], key);
			} else {
				for (key in obj)
				if (obj.hasOwnProperty(key)) {
					iterator.call(context, obj[key], key);
				}
			}
		}
		return obj;
	}

	/**
	 * @vxdoc function
	 * @name vx.extend
	 * @function
	 *
	 * @description
	 * Extends the destination object `dst` by copying all of the properties from the `src` object(s)
	 * to `dst`. You can specify multiple `src` objects.
	 *
	 * @param {Object} dst Destination object.
	 * @param {...Object} src Source object(s).
	 * @returns {Object} Reference to `dst`.
	 */
	function extend(dst) {
		var h = dst.$$hashKey;
		forEach(arguments, function(obj) {
			if (obj !== dst) {
				forEach(obj, function(value, key) {
					dst[key] = value;
				});
			}
		});
		setHashKey(dst, h);
		return dst;
	}

	function inherit(parent, extra) {
		return extend(new (extend(function() {}, {prototype:parent}))(), extra);
	}

	/**
	 * @vxdoc function
	 * @name vx.noop
	 * @function
	 *
	 * @description
	 * A function that performs no operations. This function can be useful when writing code in the
	 * functional style.
	 <pre>
	 function foo(callback) {
	 var result = calculateResult();
	 (callback || vx.noop)(result);
	 }
	 </pre>
	 */
	noop.$inject = [];
	function noop() {
	}

	/**
	 * @vxdoc function
	 * @name vx.identity
	 * @function
	 *
	 * @description
	 * A function that returns its first argument. This function is useful when writing code in the
	 * functional style.
	 *
	 <pre>
	 function transformer(transformationFn, value) {
	 return (transformationFn || identity)(value);
	 };
	 </pre>
	 */
	identity.$inject = [];
	function identity($) {
		return $;
	}

	function valueFn(value) {
		return function() {
			return value;
		};
	}

	/**
	 * @vxdoc function
	 * @name vx.isUndefined
	 * @function
	 *
	 * @description
	 * Determines if a reference is undefined.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is undefined.
	 */
	function isUndefined(value) {
		return typeof value == 'undefined';
	}

	function isEmpty(value) {
		return isUndefined(value) || value === '' || value === null || value !== value;
	}

	/**
	 * @vxdoc function
	 * @name vx.isDefined
	 * @function
	 *
	 * @description
	 * Determines if a reference is defined.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is defined.
	 */
	function isDefined(value) {
		return typeof value != 'undefined';
	}

	/**
	 * @vxdoc function
	 * @name vx.isObject
	 * @function
	 *
	 * @description
	 * Determines if a reference is an `Object`. Unlike `typeof` in JavaScript, `null`s are not
	 * considered to be objects.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is an `Object` but not `null`.
	 */
	function isObject(value) {
		return value != null && typeof value == 'object';
	}

	/**
	 * @vxdoc function
	 * @name vx.isString
	 * @function
	 *
	 * @description
	 * Determines if a reference is a `String`.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is a `String`.
	 */
	function isString(value) {
		return typeof value == 'string';
	}

	/**
	 * @vxdoc function
	 * @name vx.isNumber
	 * @function
	 *
	 * @description
	 * Determines if a reference is a `Number`.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is a `Number`.
	 */
	function isNumber(value) {
		return typeof value == 'number';
	}

	/**
	 * @vxdoc function
	 * @name vx.isDate
	 * @function
	 *
	 * @description
	 * Determines if a value is a date.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is a `Date`.
	 */
	function isDate(value) {
		return _toString.apply(value) == '[object Date]';
	}

	function isRegExp(value) {
		return _toString.apply(value) == '[object RegExp]';
	}

	/**
	 * @vxdoc function
	 * @name vx.isArray
	 * @function
	 *
	 * @description
	 * Determines if a reference is an `Array`.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is an `Array`.
	 */
	function isArray(value) {
		return _toString.apply(value) == '[object Array]';
	}

	/**
	 * @vxdoc function
	 * @name vx.isFunction
	 * @function
	 *
	 * @description
	 * Determines if a reference is a `Function`.
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is a `Function`.
	 */
	function isFunction(value) {
		return typeof value == 'function';
	}

	/**
	 * Checks if `obj` is a window object.
	 *
	 * @private
	 * @param {*} obj Object to check
	 * @returns {boolean} True if `obj` is a window obj.
	 */
	function isWindow(obj) {
		return obj && obj.document && obj.location && obj.alert && obj.setInterval;
	}

	function isScope(obj) {
		return obj && obj.$evalAsync && obj.$watch;
	}

	function isFile(obj) {
		return _toString.apply(obj) === '[object File]';
	}

	function isBoolean(value) {
		return typeof value == 'boolean';
	}

	function toBoolean(value) {
		if (value && value.length !== 0) {
			var v = lowercase("" + value);
			value = !(v == 'f' || v == '0' || v == 'false' || v == 'no' || v == 'n' || v == '[]');
		} else {
			value = false;
		}
		return value;
	}

	/**
	 * @vxdoc function
	 * @name vx.isElement
	 * @function
	 *
	 * @description
	 * Determines if a reference is a DOM element (or wrapped jQuery element).
	 *
	 * @param {*} value Reference to check.
	 * @returns {boolean} True if `value` is a DOM element (or wrapped jQuery element).
	 */
	function isElement(node) {
		// we are a direct element or part of jQuery API
		return node && (node.nodeName || (node.bind && node.find));
	}

	function includes(array, obj) {
		return indexOf(array, obj) != -1;
	}

	function indexOf(array, obj) {
		if (array.indexOf)
			return array.indexOf(obj);

		for (var i = 0, len = array.length; i < len; i++) {
			if (obj === array[i])
				return i;
		}
		return -1;
	}

	function trim(value) {
		return isString(value) ? value.replace(/^\s*/, '').replace(/\s*$/, '') : value;
	}

	/**
	 * @vxdoc function
	 * @name vx.copy
	 * @function
	 *
	 * @description
	 * Creates a deep copy of `source`, which should be an object or an array.
	 *
	 * * If no destination is supplied, a copy of the object or array is created.
	 * * If a destination is provided, all of its elements (for array) or properties (for objects)
	 *   are deleted and then all elements/properties from the source are copied to it.
	 * * If  `source` is not an object or array, `source` is returned.
	 *
	 * Note: this function is used to augment the Object type in VX expressions. See
	 * {@link vx.$filter} for more information about VX arrays.
	 *
	 * @param {*} source The source that will be used to make a copy.
	 *                   Can be any type, including primitives, `null`, and `undefined`.
	 * @param {(Object|Array)=} destination Destination into which the source is copied. If
	 *     provided, must be of the same type as `source`.
	 * @returns {*} The copy or updated `destination`, if `destination` was specified.
	 */
	function copy(source, destination) {
		if (isWindow(source) || isScope(source))
			throw vError(2, "Can't copy! Making copies of Window or Scope instances is not supported.");
		if (!destination) {
			destination = source;
			if (source) {
				if (isArray(source)) {
					destination = copy(source, []);
				} else if (isDate(source)) {
					destination = new Date(source.getTime());
				} else if (isObject(source)) {
					destination = copy(source, {});
				}
			}
		} else {
			if (source === destination)
				throw vError(3, "Can't copy! Source and destination are identical.");
			if (isArray(source)) {
				destination.length = 0;
				for (var i = 0; i < source.length; i++) {
					destination.push(copy(source[i]));
				}
			} else {
				var h = destination.$$hashKey;
				forEach(destination, function(value, key) {
					delete destination[key];
				});
				for (var key in source) {
					destination[key] = copy(source[key]);
				}
				setHashKey(destination, h);
			}
		}
		return destination;
	}

	/**
	 * Create a shallow copy of an object
	 */
	function shallowCopy(src, dst) {
		dst = dst || {};
		for (var key in src) {
			if (src.hasOwnProperty(key) && key.substr(0, 2) !== '$$') {
				dst[key] = src[key];
			}
		}
		return dst;
	}

	/**
	 * @vxdoc function
	 * @name vx.equals
	 * @function
	 *
	 * @description
	 * Determines if two objects or two values are equivalent. Supports value types, arrays and
	 * objects.
	 *
	 * Two objects or values are considered equivalent if at least one of the following is true:
	 *
	 * * Both objects or values pass `===` comparison.
	 * * Both objects or values are of the same type and all of their properties pass `===` comparison.
	 * * Both values are NaN. (In JavasScript, NaN == NaN => false. But we consider two NaN as equal)
	 *
	 * During a property comparison, properties of `function` type and properties with names
	 * that begin with `$` are ignored.
	 *
	 * Scope and DOMWindow objects are being compared only by identify (`===`).
	 *
	 * @param {*} o1 Object or value to compare.
	 * @param {*} o2 Object or value to compare.
	 * @returns {boolean} True if arguments are equal.
	 */
	function equals(o1, o2) {
		if (o1 === o2)
			return true;
		if (o1 === null || o2 === null)
			return false;
		if (o1 !== o1 && o2 !== o2)// NaN === NaN
			return true;
		var t1 = typeof o1, t2 = typeof o2, length, key, keySet;
		if (t1 == t2) {
			if (t1 == 'object') {
				if (isArray(o1)) {
					if (( length = o1.length) == o2.length) {
						for ( key = 0; key < length; key++) {
							if (!equals(o1[key], o2[key]))
								return false;
						}
						return true;
					}
				} else if (isDate(o1)) {
					return isDate(o2) && o1.getTime() == o2.getTime();
				} else {
					if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2))
						return false;
					keySet = {};
					for (key in o1) {
						if (key.charAt(0) === '$' || isFunction(o1[key]))
							continue;
						if (!equals(o1[key], o2[key]))
							return false;
						keySet[key] = true;
					}
					for (key in o2) {
						if (!keySet[key] && key.charAt(0) !== '$' && o2[key] !== undefined && !isFunction(o2[key]))
							return false;
					}
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * @vxdoc function
	 * @name vx.bind
	 * @function
	 *
	 * @description
	 * Returns a function which calls function `fn` bound to `self` (`self` becomes the `this` for
	 * `fn`). You can supply optional `args` that are prebound to the function. This feature is also
	 * known as [function currying](http://en.wikipedia.org/wiki/Currying).
	 *
	 * @param {Object} self Context which `fn` should be evaluated in.
	 * @param {function()} fn Function to be bound.
	 * @param {...*} args Optional arguments to be prebound to the `fn` function call.
	 * @returns {function()} Function that wraps the `fn` with all the specified bindings.
	 */
	function bind(self, fn) {
		var curryArgs = arguments.length > 2 ? sliceArgs(arguments, 2) : [];
		if (isFunction(fn) && !( fn instanceof RegExp)) {
			return curryArgs.length ? function() {
				return arguments.length ? fn.apply(self, curryArgs.concat(_slice.call(arguments, 0))) : fn.apply(self, curryArgs);
			} : function() {
				return arguments.length ? fn.apply(self, arguments) : fn.call(self);
			};
		} else {
			// in IE, native methods are not functions so they cannot be bound (note: they don't need to be)
			return fn;
		}
	}

	var URL_MATCH = /^([^:]+):\/\/(\w+:{0,1}\w*@)?(\{?[\w\.\-]*\}?)(:([0-9]+))?(\/[^\?#]*)?(\?([^#]*))?(#(.*))?$/, DEFAULT_PORTS = {
		'http' : 80,
		'https' : 443,
		'ftp' : 21
	};

	var URL = (function() {
		parseUrl.DEFAULT_PORTS = DEFAULT_PORTS;
		function parseUrl(url) {
			var match = URL_MATCH.exec(url);
			match = {
				protocol : match[1],
				host : match[3],
				port : int(match[5]) || DEFAULT_PORTS[match[1]] || null,
				path : match[6] || '/',
				search : match[8],
				hash : match[10]
			};
			return match;
		}

		return parseUrl;
	})();

	function concat(array1, array2, index) {
		return array1.concat(_slice.call(array2, index));
	}

	///////////////////////////////////////
	// Expr Parser
	//////////////////////////////////////
	/**
	 * Return the value accessible from the object by path. Any undefined traversals are ignored
	 * @param {Object} obj starting object
	 * @param {string} path path to traverse
	 * @param {boolean=true} bindFnToScope
	 * @returns value as accessible by path
	 */
	function getter(obj, path, bindFnToScope) {
		if (!path || !obj)
			return obj;
		var keys = path.split('.'), key, lastInstance = obj, len = keys.length;
		for (var i = 0; i < len; i++) {
			key = keys[i];
			if (obj) {
				obj = (lastInstance = obj)[key];
			}
		}
		//obj = EXPR.getter(path)(obj);
		if (!bindFnToScope && isFunction(obj)) {
			return bind(lastInstance, obj);
		}
		return obj;
	}

	var EXPR = (function() {

		var OPERATORS = {
			'null' : function() {
				return null;
			},
			'true' : function() {
				return true;
			},
			'false' : function() {
				return false;
			},
			undefined : noop,
			'+' : function(self, locals, a, b) {
				a = a(self, locals);
				b = b(self, locals);
				if (isDefined(a)) {
					if (isDefined(b)) {
						return a + b;
					}
					return a;
				}
				return isDefined(b) ? b : undefined;
			},
			'-' : function(self, locals, a, b) {
				a = a(self, locals);
				b = b(self, locals);
				return (isDefined(a) ? a : 0) - (isDefined(b) ? b : 0);
			},
			'*' : function(self, locals, a, b) {
				return a(self, locals) * b(self, locals);
			},
			'/' : function(self, locals, a, b) {
				return a(self, locals) / b(self, locals);
			},
			'%' : function(self, locals, a, b) {
				return a(self, locals) % b(self, locals);
			},
			'^' : function(self, locals, a, b) {
				return a(self, locals) ^ b(self, locals);
			},
			'=' : noop,
			'===' : function(self, locals, a, b) {
				return a(self, locals) === b(self, locals);
			},
			'!==' : function(self, locals, a, b) {
				return a(self, locals) !== b(self, locals);
			},
			'==' : function(self, locals, a, b) {
				return a(self, locals) == b(self, locals);
			},
			'!=' : function(self, locals, a, b) {
				return a(self, locals) != b(self, locals);
			},
			'<' : function(self, locals, a, b) {
				return a(self, locals) < b(self, locals);
			},
			'>' : function(self, locals, a, b) {
				return a(self, locals) > b(self, locals);
			},
			'<=' : function(self, locals, a, b) {
				return a(self, locals) <= b(self, locals);
			},
			'>=' : function(self, locals, a, b) {
				return a(self, locals) >= b(self, locals);
			},
			'&&' : function(self, locals, a, b) {
				return a(self, locals) && b(self, locals);
			},
			'||' : function(self, locals, a, b) {
				return a(self, locals) || b(self, locals);
			},
			'&' : function(self, locals, a, b) {
				return a(self, locals) & b(self, locals);
			},
			//    '|':function(self, locals, a,b){return a|b;},
			'|' : function(self, locals, a, b) {
				return b(self, locals)(self, locals, a(self, locals));
			},
			'!' : function(self, locals, a) {
				return !a(self, locals);
			}
		};
		var ESCAPE = {
			"n" : "\n",
			"f" : "\f",
			"r" : "\r",
			"t" : "\t",
			"v" : "\v",
			"'" : "'",
			'"' : '"'
		};

		function lex(text, csp) {
			var tokens = [], token, index = 0, json = [], ch, lastCh = ':';
			// can start regexp

			while (index < text.length) {
				ch = text.charAt(index);
				if (is('"\'')) {
					readString(ch);
				} else if (isDigit(ch) || is('.') && isDigit(peek())) {
					readNumber();
				} else if (isIdent(ch)) {
					readIdent();
					// identifiers can only be if the preceding char was a { or ,
					if (was('{,') && json[0] == '{' && ( token = tokens[tokens.length - 1])) {
						token.json = token.text.indexOf('.') == -1;
					}
				} else if (is('(){}[].,;:?')) {
					tokens.push({
						index : index,
						text : ch,
						json : (was(':[,') && is('{[')) || is('}]:,')
					});
					if (is('{['))
						json.unshift(ch);
					if (is('}]'))
						json.shift();
					index++;
				} else if (isWhitespace(ch)) {
					index++;
					continue;
				} else {
					var ch2 = ch + peek(), ch3 = ch2 + peek(2), fn = OPERATORS[ch], fn2 = OPERATORS[ch2], fn3 = OPERATORS[ch3];
					if (fn3) {
						tokens.push({
							index : index,
							text : ch3,
							fn : fn3
						});
						index += 3;
					} else if (fn2) {
						tokens.push({
							index : index,
							text : ch2,
							fn : fn2
						});
						index += 2;
					} else if (fn) {
						tokens.push({
							index : index,
							text : ch,
							fn : fn,
							json : was('[,:') && is('+-')
						});
						index += 1;
					} else {
						throwError("Unexpected next character ", index, index + 1);
					}
				}
				lastCh = ch;
			}
			return tokens;

			function is(chars) {
				return chars.indexOf(ch) != -1;
			}

			function was(chars) {
				return chars.indexOf(lastCh) != -1;
			}

			function peek(i) {
				var num = i || 1;
				return index + num < text.length ? text.charAt(index + num) : false;
			}

			function isDigit(ch) {
				return '0' <= ch && ch <= '9';
			}

			function isWhitespace(ch) {
				return ch == ' ' || ch == '\r' || ch == '\t' || ch == '\n' || ch == '\v' || ch == '\u00A0';
				// IE treats non-breaking space as \u00A0
			}

			function isIdent(ch) {
				return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || '_' == ch || ch == '$';
			}

			function isExpOperator(ch) {
				return ch == '-' || ch == '+' || isDigit(ch);
			}

			function throwError(error, start, end) {
				end = end || index;
				var colStr = (isDefined(start) ? "s " + start + "-" + index + " [" + text.substring(start, end) + "]" : " " + end);
				throw vError(10, "Lexer Error: {0} at column{1} in expression [{2}].", error, colStr, text);
			}

			function readNumber() {
				var number = "";
				var start = index;
				while (index < text.length) {
					var ch = lowercase(text.charAt(index));
					if (ch == '.' || isDigit(ch)) {
						number += ch;
					} else {
						var peekCh = peek();
						if (ch == 'e' && isExpOperator(peekCh)) {
							number += ch;
						} else if (isExpOperator(ch) && peekCh && isDigit(peekCh) && number.charAt(number.length - 1) == 'e') {
							number += ch;
						} else if (isExpOperator(ch) && (!peekCh || !isDigit(peekCh)) && number.charAt(number.length - 1) == 'e') {
							throwError('Invalid exponent');
						} else {
							break;
						}
					}
					index++;
				}
				number = 1 * number;
				tokens.push({
					index : start,
					text : number,
					json : true,
					fn : function() {
						return number;
					}
				});
			}

			function readIdent() {
				var ident = "", start = index, lastDot, peekIndex, methodName, ch;

				while (index < text.length) {
					ch = text.charAt(index);
					if (ch == '.' || isIdent(ch) || isDigit(ch)) {
						if (ch == '.')
							lastDot = index;
						ident += ch;
					} else {
						break;
					}
					index++;
				}

				//check if this is not a method invocation and if it is back out to last dot
				if (lastDot) {
					peekIndex = index;
					while (peekIndex < text.length) {
						ch = text.charAt(peekIndex);
						if (ch == '(') {
							methodName = ident.substr(lastDot - start + 1);
							ident = ident.substr(0, lastDot - start);
							index = peekIndex;
							break;
						}
						if (isWhitespace(ch)) {
							peekIndex++;
						} else {
							break;
						}
					}
				}

				var token = {
					index : start,
					text : ident
				};

				if (OPERATORS.hasOwnProperty(ident)) {
					token.fn = token.json = OPERATORS[ident];
				} else {
					var getter = getterFn(ident, csp);
					token.fn = extend(function(self, locals) {
						return (getter(self, locals));
					}, {
						assign : function(self, value) {
							return setter(self, ident, value);
						}
					});
				}

				tokens.push(token);

				if (methodName) {
					tokens.push({
						index : lastDot,
						text : '.',
						json : false
					});
					tokens.push({
						index : lastDot + 1,
						text : methodName,
						json : false
					});
				}
			}

			function readString(quote) {
				var start = index;
				index++;
				var string = "", stringFn = function() {
					return string;
				};
				var rawString = quote;
				var escape = false;
				while (index < text.length) {
					var ch = text.charAt(index);
					rawString += ch;
					if (escape) {
						if (ch == 'u') {
							var hex = text.substring(index + 1, index + 5);
							if (!hex.match(/[\da-f]{4}/i))
								throwError("Invalid unicode escape [\\u" + hex + "]");
							index += 4;
							string += String.fromCharCode(parseInt(hex, 16));
						} else {
							var rep = ESCAPE[ch];
							if (rep) {
								string += rep;
							} else {
								string += ch;
							}
						}
						escape = false;
					} else if (ch == '\\') {
						escape = true;
					} else if (ch == quote) {
						index++;
						tokens.push({
							index : start,
							text : rawString,
							string : string,
							json : true,
							fn : stringFn
						});
						return;
					} else {
						string += ch;
					}
					index++;
				}
				throwError("Unterminated quote", start);
			}

		}

		function parser(text, json, $filter, csp) {
			var ZERO = valueFn(0), value, tokens = lex(text, csp), assignment = _assignment, functionCall = _functionCall, //
			fieldAccess = _fieldAccess, objectIndex = _objectIndex, filterChain = _filterChain;
			if (json) {
				// The extra level of aliasing is here, just in case the lexer misses something, so that
				// we prevent any accidental execution in JSON.
				assignment = logicalOR;
				functionCall = fieldAccess = objectIndex = filterChain = function() {
					throwError("is not valid json.json", {
						text : text,
						index : 0
					});
				};
				value = primary();
			} else {
				value = statements();
			}
			if (tokens.length !== 0) {
				throwError("is an unexpected token", tokens[0]);
			}
			value.literal = !!value.literal;
			value.constant = !!value.constant;
			return value;

			//---------------------------------------
			function throwError(msg, token) {
				throw vError(11, "Syntax Error: Token '{0}' {1} at column {2} of the expression [{3}] starting at [{4}].", token.text, msg, (token.index + 1), text, text.substring(token.index));
			}

			function peekToken() {
				if (tokens.length === 0)
					throw vError(12, "Unexpected end of expression: {0}", text);
				return tokens[0];
			}

			function peek(e1, e2, e3, e4) {
				if (tokens.length > 0) {
					var token = tokens[0];
					var t = token.text;
					if (t == e1 || t == e2 || t == e3 || t == e4 || (!e1 && !e2 && !e3 && !e4)) {
						return token;
					}
				}
				return false;
			}

			function expect(e1, e2, e3, e4) {
				var token = peek(e1, e2, e3, e4);
				if (token) {
					if (json && !token.json) {
						throwError("is not valid json.json", token);
					}
					tokens.shift();
					return token;
				}
				return false;
			}

			function consume(e1) {
				if (!expect(e1)) {
					throwError("is unexpected, expecting [" + e1 + "]", peek());
				}
			}

			function unaryFn(fn, right) {
				return extend(function(self, locals) {
					return fn(self, locals, right);
				}, {
					constant : right.constant
				});
			}

			function ternaryFn(left, middle, right) {
				return extend(function(self, locals) {
					return left(self, locals) ? middle(self, locals) : right(self, locals);
				}, {
					constant : left.constant && middle.constant && right.constant
				});
			}

			function binaryFn(left, fn, right) {
				return extend(function(self, locals) {
					return fn(self, locals, left, right);
				}, {
					constant : left.constant && right.constant
				});
			}

			function statements() {
				var _statements = [], fn = function(self, locals) {
					var value;
					for (var i = 0; i < _statements.length; i++) {
						var statement = _statements[i];
						if (statement)
							value = statement(self, locals);
					}
					return value;
				};
				while (true) {
					if (tokens.length > 0 && !peek('}', ')', ';', ']'))
						_statements.push(filterChain());
					if (!expect(';')) {
						// optimize for the common case where there is only one statement.
						// TODO(size): maybe we should not support multiple statements?
						return _statements.length == 1 ? _statements[0] : fn;
					}
				}
			}

			function _filterChain() {
				var left = expression();
				var token;
				while (true) {
					if (( token = expect('|'))) {
						left = binaryFn(left, token.fn, filter());
					} else {
						return left;
					}
				}
			}

			function filter() {
				var token = expect();
				var fn = $filter(token.text);
				var argsFn = [];
				var fnInvoke = function(self, locals, input) {
					var args = [input];
					for (var i = 0; i < argsFn.length; i++) {
						args.push(argsFn[i](self, locals));
					}
					return fn.apply(self, args);
				}, fn1 = function() {
					return fnInvoke;
				};
				while (true) {
					if (( token = expect(':'))) {
						argsFn.push(expression());
					} else {
						return fn1;
					}
				}
			}

			function expression() {
				return assignment();
			}

			function _assignment() {
				var left = ternary();
				var right;
				var token;
				if (( token = expect('='))) {
					if (!left.assign) {
						throwError("implies assignment but [" + text.substring(0, token.index) + "] can not be assigned to", token);
					}
					right = ternary();
					return function(scope, locals) {
						return left.assign(scope, right(scope, locals), locals);
					};
				} else {
					return left;
				}
			}

			function ternary() {
				var left = logicalOR();
				var middle;
				var token;
				if (( token = expect('?'))) {
					middle = ternary();
					if (( token = expect(':'))) {
						return ternaryFn(left, middle, ternary());
					} else {
						throwError('expected :', token);
					}
				} else {
					return left;
				}
			}

			function logicalOR() {
				var left = logicalAND();
				var token;
				while (true) {
					if (( token = expect('||'))) {
						left = binaryFn(left, token.fn, logicalAND());
					} else {
						return left;
					}
				}
			}

			function logicalAND() {
				var left = equality();
				var token;
				if (( token = expect('&&'))) {
					left = binaryFn(left, token.fn, logicalAND());
				}
				return left;
			}

			function equality() {
				var left = relational();
				var token;
				if (( token = expect('==', '!=', '===', '!=='))) {
					left = binaryFn(left, token.fn, equality());
				}
				return left;
			}

			function relational() {
				var left = additive();
				var token;
				if (( token = expect('<', '>', '<=', '>='))) {
					left = binaryFn(left, token.fn, relational());
				}
				return left;
			}

			function additive() {
				var left = multiplicative();
				var token;
				while (( token = expect('+', '-'))) {
					left = binaryFn(left, token.fn, multiplicative());
				}
				return left;
			}

			function multiplicative() {
				var left = unary();
				var token;
				while (( token = expect('*', '/', '%'))) {
					left = binaryFn(left, token.fn, unary());
				}
				return left;
			}

			function unary() {
				var token;
				if (expect('+')) {
					return primary();
				} else if (( token = expect('-'))) {
					return binaryFn(ZERO, token.fn, unary());
				} else if (( token = expect('!'))) {
					return unaryFn(token.fn, unary());
				} else {
					return primary();
				}
			}

			function primary() {
				var _primary;
				if (expect('(')) {
					_primary = filterChain();
					consume(')');
				} else if (expect('[')) {
					_primary = arrayDeclaration();
				} else if (expect('{')) {
					_primary = object();
				} else {
					var token = expect();
					_primary = token.fn;
					if (!_primary) {
						throwError("not a primary expression", token);
					}
					if (token.json) {
						primary.constant = primary.literal = true;
					}
				}

				var next, context;
				while (( next = expect('(', '[', '.'))) {
					if (next.text === '(') {
						_primary = functionCall(_primary, context);
						context = null;
					} else if (next.text === '[') {
						context = _primary;
						_primary = objectIndex(_primary);
					} else if (next.text === '.') {
						context = _primary;
						_primary = fieldAccess(_primary);
					} else {
						throwError("IMPOSSIBLE");
					}
				}
				return _primary;
			}

			function _fieldAccess(object) {
				var field = expect().text;
				var getter = getterFn(field, csp);
				return extend(function(scope, locals, self) {
					return getter(self || object(scope, locals), locals);
				}, {
					assign : function(scope, value, locals) {
						var o = object(scope, locals);
						// in a.b[3].c, when b is null
						if (o == null)
							o = object.assign(scope, {}, locals);
						return setter(o, field, value);
					}
				});
			}

			function _objectIndex(obj) {
				var indexFn = expression();
				consume(']');
				return extend(function(self, locals) {
					var o = obj(self, locals), i = indexFn(self, locals), v, p;
					if (!o)
						return undefined;
					v = o[i];
					if (v && v.then) {
						p = v;
						if (!('$$v' in v)) {
							p.$$v = undefined;
							p.then(function(val) {
								p.$$v = val;
							});
						}
						v = v.$$v;
					}
					return v;
				}, {
					assign : function(self, value, locals) {
						var arr = obj(self, locals), i = indexFn(self, locals);
						// if not found, new array
						if (arr == null)
							arr = obj.assign(self, isString(i) ? {} : []);
						return arr[i] = value;
					}
				});
			}

			function _functionCall(fn, contextGetter) {
				var argsFn = [];
				if (peekToken().text != ')') {
					do {
						argsFn.push(expression());
					} while (expect(','));
				}
				consume(')');
				return function(scope, locals) {
					var args = [], context = contextGetter ? contextGetter(scope, locals) : scope;

					for (var i = 0; i < argsFn.length; i++) {
						args.push(argsFn[i](scope, locals));
					}
					var fnPtr = fn(scope, locals, context) || noop;
					// IE stupidity!
					//return fnPtr.apply ? fnPtr.apply(context, args) : fnPtr(args[0], args[1], args[2], args[3], args[4]);
					return _fastInvoke(fnPtr, context, args);
				};
			}

			// This is used with json.json array declaration
			function arrayDeclaration() {
				var elementFns = [];
				var allConstant = true;
				if (peekToken().text != ']') {
					do {
						var elementFn = expression();
						elementFns.push(elementFn);
						if (!elementFn.constant) {
							allConstant = false;
						}
					} while (expect(','));
				}
				consume(']');
				return extend(function(self, locals) {
					var array = [];
					for (var i = 0; i < elementFns.length; i++) {
						array.push(elementFns[i](self, locals));
					}
					return array;
				}, {
					literal : true,
					constant : allConstant
				});
			}

			function object() {
				var keyValues = [];
				var allConstant = true;
				if (peekToken().text != '}') {
					do {
						var token = expect(), key = token.string || token.text;
						consume(":");
						var value = expression();
						keyValues.push({
							key : key,
							value : value
						});
						if (!value.constant) {
							allConstant = false;
						}
					} while (expect(','));
				}
				consume('}');
				return extend(function(self, locals) {
					var object = {};
					for (var i = 0; i < keyValues.length; i++) {
						var keyValue = keyValues[i];
						object[keyValue.key] = keyValue.value(self, locals);
					}
					return object;
				}, {
					literal : true,
					constant : allConstant
				});
			}

		}

		//*****************************
		// Parser helper functions
		//*****************************

		function setter(obj, path, setValue) {
			var element = path.split('.');
			for (var i = 0; element.length > 1; i++) {
				var key = element.shift();
				var propertyObj = obj[key];
				if (!propertyObj) {
					propertyObj = {};
					obj[key] = propertyObj;
				}
				obj = propertyObj;
			}
			obj[element.shift()] = setValue;
			return setValue;
		}

		var getterFnCache = {};

		/**
		 * Implementation of the "Black Hole" variant from:
		 * - http://jsperf.com/vxjs-parse-getter/4
		 * - http://jsperf.com/path-evaluation-simplified/7
		 */
		function cspSafeGetterFn(key0, key1, key2, key3, key4) {
			return function(scope, locals) {
				var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope, promise;

				if (pathVal === null || pathVal === undefined)
					return pathVal;
				pathVal = pathVal[key0];
				if (pathVal && pathVal.then) {
					if (!("$$v" in pathVal)) {
						promise = pathVal;
						promise.$$v = undefined;
						promise.then(function(val) {
							promise.$$v = val;
						});
					}
					pathVal = pathVal.$$v;
				}
				if (!key1 || pathVal === null || pathVal === undefined)
					return pathVal;
				pathVal = pathVal[key1];
				if (pathVal && pathVal.then) {
					if (!("$$v" in pathVal)) {
						promise = pathVal;
						promise.$$v = undefined;
						promise.then(function(val) {
							promise.$$v = val;
						});
					}
					pathVal = pathVal.$$v;
				}
				if (!key2 || pathVal === null || pathVal === undefined)
					return pathVal;
				pathVal = pathVal[key2];
				if (pathVal && pathVal.then) {
					if (!("$$v" in pathVal)) {
						promise = pathVal;
						promise.$$v = undefined;
						promise.then(function(val) {
							promise.$$v = val;
						});
					}
					pathVal = pathVal.$$v;
				}
				if (!key3 || pathVal === null || pathVal === undefined)
					return pathVal;
				pathVal = pathVal[key3];
				if (pathVal && pathVal.then) {
					if (!("$$v" in pathVal)) {
						promise = pathVal;
						promise.$$v = undefined;
						promise.then(function(val) {
							promise.$$v = val;
						});
					}
					pathVal = pathVal.$$v;
				}
				if (!key4 || pathVal === null || pathVal === undefined)
					return pathVal;
				pathVal = pathVal[key4];
				if (pathVal && pathVal.then) {
					if (!("$$v" in pathVal)) {
						promise = pathVal;
						promise.$$v = undefined;
						promise.then(function(val) {
							promise.$$v = val;
						});
					}
					pathVal = pathVal.$$v;
				}
				return pathVal;
			};
		}

		function getterFn(path, csp) {
			if (getterFnCache.hasOwnProperty(path)) {
				return getterFnCache[path];
			}

			var pathKeys = path.split('.'), pathKeysLength = pathKeys.length, fn;

			if (csp) {
				fn = (pathKeysLength < 6) ? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4]) : function(scope, locals) {
					var i = 0, val;
					do {
						val = cspSafeGetterFn(
						pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++]
						)(scope, locals);
						locals = undefined;
						// clear after first iteration
						scope = val;
					} while (i < pathKeysLength);
					return val;
				};
			} else {
				var code = 'var l, fn, p;\n';
				forEach(pathKeys, function(key, index) {
					code += 'if(s === null || s === undefined) return s;\n' + 'l=s;\n' + 's=' + ( index
					// we simply dereference 's' on any .dot notation
					? 's'
					// but if we are first then we check locals first, and if so read it first
					: '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' + //
					'if (s && s.then) {\n' + ' if (!("$$v" in s)) {\n' + ' p=s;\n' + //
					' p.$$v = undefined;\n' + ' p.then(function(v) {p.$$v=v;});\n' + '}\n' + ' s=s.$$v\n' + '}\n';
				});
				code += 'return s;';
				/*jshint evil:true*/
				fn = new Function('s', 'k', code);
				// s=scope, k=locals
				fn.toString = function() {
					return code;
				};
			}

			return getterFnCache[path] = fn;
		}

		return {
			parser : parser,
			getter : getterFn
		};
	})();

	/////////////////////////////////////
	// JSON
	///////////////////////////////////
	/**
	 * @vxdoc function
	 * @name vx.toJson
	 * @function
	 *
	 * @description
	 * Serializes input into a JSON-formatted string.
	 *
	 * @param {Object|Array|Date|string|number} obj Input to be serialized into JSON.
	 * @param {boolean=} pretty If set to true, the JSON output will contain newlines and whitespace.
	 * @returns {string} Jsonified string representing `obj`.
	 */
	var toJson = (function() {
		return function(obj, pretty) {
			if (window.JSON && window.JSON.stringify)
				return JSON.stringify(obj, toJsonReplacer, pretty ? '  ' : null);
			var buf = [];
			toJsonArray(buf, obj, pretty ? "\n  " : null, []);
			return buf.join('');
		};
		function toJsonReplacer(key, value) {
			var val = value;
			if (/^\$+/.test(key) || 'this' === key) {
				val = undefined;
			} else if (isWindow(value)) {
				val = '$WINDOW';
			} else if (value && document === value) {
				val = '$DOCUMENT';
			} else if (isScope(value)) {
				val = '$SCOPE';
			}
			return val;
		}

		function jsonDateToString(date) {
			if (!date)
				return date;
			var isoString = date.toISOString ? date.toISOString() : '';
			return (isoString.length == 24) ? isoString : padNumber(date.getUTCFullYear(), 4) + '-' + //
			padNumber(date.getUTCMonth() + 1, 2) + '-' + padNumber(date.getUTCDate(), 2) + 'T' + //
			padNumber(date.getUTCHours(), 2) + ':' + padNumber(date.getUTCMinutes(), 2) + ':' + //
			padNumber(date.getUTCSeconds(), 2) + '.' + padNumber(date.getUTCMilliseconds(), 3) + 'Z';
		}

		function quoteUnicode(string, pretty) {
			var chars = ['"'];
			for (var i = 0; i < string.length; i++) {
				var code = string.charCodeAt(i);
				var ch = string.charAt(i);
				switch(ch) {
					case '"':
						chars.push('\\"');
						break;
					case '\\':
						chars.push('\\\\');
						break;
					case '\n':
						chars.push('\\n');
						break;
					case '\f':
						chars.push('\\f');
						break;
					case '\r':
						chars.push( ch = '\\r');
						break;
					case '\t':
						chars.push( ch = '\\t');
						break;
					default:
						if (pretty)
							chars.push(ch);
						else {
							if (32 <= code && code <= 126) {
								chars.push(ch);
							} else {
								var encode = "000" + code.toString(16);
								chars.push("\\u" + encode.substring(encode.length - 4));
							}
						}
				}
			}
			chars.push('"');
			return chars.join('');
		}

		function toJsonArray(buf, obj, pretty, stack) {
			if (isObject(obj)) {
				if (obj === window) {
					buf.push('WINDOW');
					return;
				}
				if (obj === document) {
					buf.push('DOCUMENT');
					return;
				}
				if (includes(stack, obj)) {
					buf.push('RECURSION');
					return;
				}
				stack.push(obj);
			}
			if (obj === null) {
				buf.push('null');
			} else if ( obj instanceof RegExp) {
				buf.push(quoteUnicode(obj.toString(), pretty));
			} else if (isFunction(obj)) {
				return;
			} else if (isBoolean(obj)) {
				buf.push('' + obj);
			} else if (isNumber(obj)) {
				if (isNaN(obj)) {
					buf.push('null');
				} else {
					buf.push('' + obj);
				}
			} else if (isString(obj)) {
				return buf.push(quoteUnicode(obj, pretty));
			} else if (isObject(obj)) {
				if (isArray(obj)) {
					buf.push("[");
					var len = obj.length;
					var sep = false;
					for (var i = 0; i < len; i++) {
						var item = obj[i];
						if (sep)
							buf.push(",");
						if (!( item instanceof RegExp) && (isFunction(item) || isUndefined(item))) {
							buf.push('null');
						} else {
							toJsonArray(buf, item, pretty, stack);
						}
						sep = true;
					}
					buf.push("]");
				} else if (isElement(obj)) {
					// TODO(misko): maybe in dev mode have a better error reporting?
					buf.push('DOM_ELEMENT');
				} else if (isDate(obj)) {
					buf.push(quoteUnicode(jsonDateToString(obj), pretty));
				} else {
					buf.push("{");
					if (pretty)
						buf.push(pretty);
					var comma = false;
					var childPretty = pretty ? pretty + "  " : false;
					var keys = [];
					for (var k in obj) {
						if (k != 'this' && k.substring(0, 1) != '$' && obj.hasOwnProperty(k) && obj[k] !== undefined) {
							keys.push(k);
						}
					}
					keys.sort();
					for (var keyIndex = 0; keyIndex < keys.length; keyIndex++) {
						var key = keys[keyIndex];
						var value = obj[key];
						if (!isFunction(value)) {
							if (comma) {
								buf.push(",");
								if (pretty)
									buf.push(pretty);
							}
							buf.push(quoteUnicode(key, pretty));
							buf.push(":");
							toJsonArray(buf, value, childPretty, stack);
							comma = true;
						}
					}
					buf.push("}");
				}
			}
			if (isObject(obj)) {
				stack.pop();
			}
		}

	})();

	/**
	 * @vxdoc function
	 * @name vx.fromJson
	 * @function
	 *
	 * @description
	 * Deserializes a JSON string.
	 *
	 * @param {string} json JSON string to deserialize.
	 * @returns {Object|Array|Date|string|number} Deserialized thingy.
	 */
	function fromJson(json) {
		if (!isString(json))
			return json;
		if (window.JSON && window.JSON.parse) {
			return JSON.parse(json);
		} else {
			return EXPR.parser(json, true)();
		}
	}

	//////////////////////////////////
	//  JQLite
	//////////////////////////////////

	/**
	 * @vxdoc function
	 * @name vx.element
	 * @function
	 *
	 * @description
	 * Wraps a raw DOM element or HTML string as a [jQuery](http://jquery.com) element.
	 * `vx.element` can be either an alias for [jQuery](http://api.jquery.com/jQuery/) function, if
	 * jQuery is available, or a function that wraps the element or string in VX's jQuery lite
	 * implementation (commonly referred to as jqLite).
	 *
	 * Real jQuery always takes precedence over jqLite, provided it was loaded before `DOMContentLoaded`
	 * event fired.
	 *
	 * jqLite is a tiny, API-compatible subset of jQuery that allows
	 * VX to manipulate the DOM. jqLite implements only the most commonly needed functionality
	 * within a very small footprint, so only a subset of the jQuery API - methods, arguments and
	 * invocation styles - are supported.
	 *
	 * Note: All element references in VX are always wrapped with jQuery or jqLite; they are never
	 * raw DOM references.
	 *
	 * ## VX's jQuery lite provides the following methods:
	 *
	 * - [addClass()](http://api.jquery.com/addClass/)
	 * - [after()](http://api.jquery.com/after/)
	 * - [append()](http://api.jquery.com/append/)
	 * - [attr()](http://api.jquery.com/attr/)
	 * - [bind()](http://api.jquery.com/bind/)
	 * - [children()](http://api.jquery.com/children/)
	 * - [clone()](http://api.jquery.com/clone/)
	 * - [contents()](http://api.jquery.com/contents/)
	 * - [css()](http://api.jquery.com/css/)
	 * - [data()](http://api.jquery.com/data/)
	 * - [eq()](http://api.jquery.com/eq/)
	 * - [find()](http://api.jquery.com/find/) - Limited to lookups by tag name.
	 * - [hasClass()](http://api.jquery.com/hasClass/)
	 * - [html()](http://api.jquery.com/html/)
	 * - [next()](http://api.jquery.com/next/)
	 * - [parent()](http://api.jquery.com/parent/)
	 * - [prepend()](http://api.jquery.com/prepend/)
	 * - [prop()](http://api.jquery.com/prop/)
	 * - [ready()](http://api.jquery.com/ready/)
	 * - [remove()](http://api.jquery.com/remove/)
	 * - [removeAttr()](http://api.jquery.com/removeAttr/)
	 * - [removeClass()](http://api.jquery.com/removeClass/)
	 * - [removeData()](http://api.jquery.com/removeData/)
	 * - [replaceWith()](http://api.jquery.com/replaceWith/)
	 * - [text()](http://api.jquery.com/text/)
	 * - [toggleClass()](http://api.jquery.com/toggleClass/)
	 * - [triggerHandler()](http://api.jquery.com/triggerHandler/) - Passes a dummy event object to handlers.
	 * - [unbind()](http://api.jquery.com/unbind/)
	 * - [val()](http://api.jquery.com/val/)
	 * - [wrap()](http://api.jquery.com/wrap/)
	 *
	 * ## In addition to the above, VX privides additional methods to both jQuery and jQuery lite:
	 *
	 * - `controller(name)` - retrieves the controller of the current element or its parent. By default
	 *   retrieves controller associated with the `vController` directive. If `name` is provided as
	 *   camelCase directive name, then the controller for this directive will be retrieved (e.g.
	 *   `'vModel'`).
	 * - `injector()` - retrieves the injector of the current element or its parent.
	 * - `scope()` - retrieves the {@link api/vx.$rootScope.Scope scope} of the current
	 *   element or its parent.
	 * - `inheritedData()` - same as `data()`, but walks up the DOM until a value is found or the top
	 *   parent element is reached.
	 *
	 * @param {string|DOMElement} element HTML string or DOMElement to be wrapped into jQuery.
	 * @returns {Object} jQuery object.
	 */
	function bindJQuery() {
		if (jqLite) {
			var bindFn = jqLite.fn.bind, attrFn = jqLite.fn.attr;
			extend(jqLite.fn, {
				inheritedData : function(name, value) {
					return jqLiteInheritedData(this, name, value);
				},
				scope : function() {
					return this.inheritedData('$scope');
				},
				injector : function() {
					return this.inheritedData('$injector');
				},
				controller : function(name) {
					return this.inheritedData('$' + (name || 'vController' ) + 'Controller');
				},
				bind : function(name, handler) {
					var proxy = name, fn = handler, target = this[0];
					if (name === 'mouseenter' || name === 'mouseleave') {
						var contains = document.body.contains || document.body.compareDocumentPosition ? function(a, b) {
							var adown = a.nodeType === 9 ? a.documentElement : a, bup = b && b.parentNode;
							return a === bup || !!(bup && bup.nodeType === 1 && (adown.contains ? adown.contains(bup) : a.compareDocumentPosition && a.compareDocumentPosition(bup) & 16
							));
						} : function(a, b) {
							if (b) {
								while (( b = b.parentNode)) {
									if (b === a) {
										return true;
									}
								}
							}
							return false;
						};

						// Refer to jQuery's implementation of mouseenter & mouseleave
						// Read about mouseenter and mouseleave:
						// http://www.quirksmode.org/js/events_mouse.html#link8
						var eventmap = {
							mouseleave : "mouseout",
							mouseenter : "mouseover"
						};
						proxy = eventmap[name];
						fn = function(event) {
							var ret, target = this, related = event.relatedTarget;
							// For mousenter/leave call the handler if related is outside the target.
							// NB: No relatedTarget if the mouse left/entered the browser window
							if (!related || (related !== target && !contains(target, related))) {
								handler(event, name);
							}

						};
					}
					return bindFn.call(this, proxy, fn);
				},
				attr : function(attrName, value) {
					//*** jimmy, fix IE cannot modify 'name' and 'id' of element (eg. <input name='...'>)
					// only for IE 6, 7
					if (value !== undefined && msie < 8 && (attrName == 'name' || attrName == 'id')) {
						/**
						 *ChenLin
						 *  fix SCRIPT5022:DOM Exception
						 */
						var html = jqLite("<input " + attrName + "='" + value + "'/>");
						if (this && this.length > 0)
							this[0].mergeAttributes(html[0], false);
						return this;
					} else
						return value === undefined ? attrFn.call(this, attrName) : attrFn.call(this, attrName, value);
				}
			});
			// Method signature: jqLitePatchRemove(name, dispatchThis, filterElems, getterIfNoArguments)
			jqLitePatchRemove('remove', true, true, false);
			jqLitePatchRemove('empty', false, false, false);
			jqLitePatchRemove('html', false, false, true);
		} else {
			throw vError(20, 'no jQuery found');
		}

		function contains(p, c) {
			return p.contains ? p != c && p.contains(c) : !!(p.compareDocumentPosition(c) & 16);
		}

		function jqLiteInheritedData(element, name, value) {
			// if element is the document object work with the html element instead
			// this makes $(document).scope() possible
			if (element.length && element[0].nodeType == 9) {
				element = element.find('html');
			}

			while (element.length) {
				/*jshint boss:true*/
				if ( value = element.data(name))
					return value;
				element = element.parent();
			}
		}

		/////////////////////////////////////////////
		// jQuery mutation patch
		//
		//  In conjunction with bindJQuery intercepts all jQuery's DOM destruction APIs and fires a
		// $destroy event on all DOM nodes being removed.
		//
		/////////////////////////////////////////////
		function jqLitePatchRemove(name, dispatchThis, filterElems, getterIfNoArguments) {
			var originalJqFn = original(name);
			removePatch.$original = originalJqFn;
			jqLite.fn[name] = removePatch;

			function original(name) {
				var old = jqLite.fn[name];
				return old.$original || old;
			}

			function removePatch(param) {
				/*jshint validthis:true*/
				var list = filterElems && param ? [this.filter(param)] : [this], //
				fireEvent = dispatchThis, set, setIndex, setLength, element, childIndex, childLength, children;

				if (!getterIfNoArguments || param != null) {
					while (list.length) {
						set = list.shift();
						for ( setIndex = 0, setLength = set.length; setIndex < setLength; setIndex++) {
							element = jqLite(set[setIndex]);
							if (fireEvent) {
								if (element.triggerHandler)
									element.triggerHandler('$destroy');
								if (element.unbindAll) {// for zepto and jqmobi
									element.unbindAll();
									if (element.removeData)
										element.removeData();
								}
							} else {
								fireEvent = !fireEvent;
							}
							for ( childIndex = 0, childLength = ( children = element.children()).length; childIndex < childLength; childIndex++) {
								list.push(jqLite(children[childIndex]));
							}
						}
					}
				}

				if (!msie)
					return originalJqFn.apply(this, arguments);

				var i, me = name === 'remove' ? this : this.contents(), olds = [], ret;
				for ( i = 0; i < me.length; i++)
					olds.push(me[i]);

				if (name === 'html')
					ret = original('empty').apply(this);
				else
					ret = originalJqFn.apply(this, arguments);

				for ( i = 0; i < olds.length; i++)
					IE_GC(olds[i]);

				return name === 'html' ? originalJqFn.apply(ret, arguments) : ret;
			}

		}

	}

	function jqLiteClone(element) {
		if (element && element.cloneNode) {
			return element.cloneNode(true);
		}
		var el;
		for (var i = 0; i < element.length; i++) {
			if (el === undefined) {
				el = jqLite(jqLiteClone(element[i]));
			} else {
				el.push(jqLiteClone(element[i]));
			}
		}
		return el === undefined ? element : el;
	}

	/**
	 * Parses an escaped url query string into key-value pairs.
	 * @returns Object.<(string|boolean)>
	 */
	function parseKeyValue(/**string*/keyValue) {
		var obj = {}, key_value, key;
		vx.forEach((keyValue || "").split('&'), function(keyValue) {
			if (keyValue) {
				key_value = keyValue.split('=');
				key = decodeURIComponent(key_value[0]);
				obj[key] = isDefined(key_value[1]) ? decodeURIComponent(key_value[1]) : true;
			}
		});
		return obj;
	}

	function toKeyValue(obj) {
		var parts = [];
		vx.forEach(obj, function(value, key) {
			parts.push(encodeUriQuery(key, true) + (value === true ? '' : '=' + encodeUriQuery(value, true)));
		});
		return parts.length ? parts.join('&') : '';
	}

	/**
	 * We need our custom method because encodeURIComponent is too aggressive and doesn't follow
	 * http://www.ietf.org/rfc/rfc3986.txt with regards to the character set (pchar) allowed in path
	 * segments:
	 *    segment       = *pchar
	 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
	 *    pct-encoded   = "%" HEXDIG HEXDIG
	 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
	 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
	 *                     / "*" / "+" / "," / ";" / "="
	 */
	function encodeUriSegment(val) {
		return encodeUriQuery(val, true).replace(/%26/gi, '&').replace(/%3D/gi, '=').replace(/%2B/gi, '+');
	}

	/**
	 * This method is intended for encoding *key* or *value* parts of query component. We need a custom
	 * method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
	 * encoded per http://tools.ietf.org/html/rfc3986:
	 *    query       = *( pchar / "/" / "?" )
	 *    pchar         = unreserved / pct-encoded / sub-delims / ":" / "@"
	 *    unreserved    = ALPHA / DIGIT / "-" / "." / "_" / "~"
	 *    pct-encoded   = "%" HEXDIG HEXDIG
	 *    sub-delims    = "!" / "$" / "&" / "'" / "(" / ")"
	 *                     / "*" / "+" / "," / ";" / "="
	 */
	function encodeUriQuery(val, pctEncodeSpaces) {
		return encodeURIComponent(val).replace(/%40/gi, '@').replace(/%3A/gi, ':').replace(/%24/g, '$')//
		.replace(/%2C/gi, ',').replace(/%20/g, ( pctEncodeSpaces ? '%20' : '+'));
	}

	///////////////////////////////
	// vx config
	//////////////////////////////

	/**
	 * @vxdoc property
	 * @name vx.version
	 * @description
	 * An object that contains information about the current VXJS version. This object has the
	 * following properties:
	 *
	 * - `full` – `{string}` – Full version string, such as "0.9.18".
	 * - `major` – `{number}` – Major version number, such as "0".
	 * - `minor` – `{number}` – Minor version number, such as "9".
	 * - `dot` – `{number}` – Dot version number, such as "18".
	 * - `codeName` – `{string}` – Code name of the release, such as "jiggling-armfat".
	 */
	var version = {
		full : '1.1.5', // all of these placeholder strings will be replaced by rake's
		major : 1, // compile task
		minor : 1,
		dot : 5,
		codeName : 'Venus UltraView - (VX)'
	};

	function vxSetup(vx) {
		bindJQuery();
		extend(vx, {
			'cleanupClosure' : cleanupClosure,
			'vError' : vError,
			'formatError' : formatError,
			'$TIMESTAMP' : now(),
			'$UUID' : uuid(),
			'define' : define,
			'msie' : msie, //
			'URL' : URL,
			'uid' : function() {
				return nextUid(VID);
			},
			'uuid' : uuid,
			'now' : now,
			'version' : version,
			'module' : moduler(),
			'init' : vxInit, //
			'bootstrap' : bootstrap,
			'injector' : createInjector,
			'element' : jqLite,

			'copy' : copy,
			//'shallowCopy' : shallowCopy,
			'equals' : equals,
			'extend' : extend,
			'inherit' : inherit,
			'bind' : bind,
			'forEach' : forEach,
			'noop' : noop,
			'identity' : identity,
			'valueFn' : valueFn, //

			'toJson' : toJson,
			'fromJson' : fromJson,

			'isUndefined' : isUndefined,
			'isDefined' : isDefined,
			'isEmpty' : isEmpty,
			'isFile' : isFile,
			'isBoolean' : isBoolean,
			'toBoolean' : toBoolean,
			'isString' : isString,
			'isFunction' : isFunction,
			'isObject' : isObject,
			'isNumber' : isNumber,
			'isElement' : isElement,
			'isArray' : isArray,
			'isDate' : isDate,
			'isRegExp' : isRegExp,
			'isWindow' : isWindow,
			'isScope' : isScope,

			'lowercase' : lowercase,
			'uppercase' : uppercase,
			'trim' : trim,
			'includes' : includes,
			'indexOf' : indexOf,
			//'concat' : concat,

			'parseKeyValue' : parseKeyValue,
			'toKeyValue' : toKeyValue,
			'encodeUriSegment' : encodeUriSegment, //
			'encodeUriQuery' : encodeUriQuery,
			'_nodeName' : _nodeName,

			'callbacks' : {//XXX by jsonp
				counter : 0
			}
		});
		// defined core modules
		vx.module('vLocale', []).value('$locale', {});
		vx.module('v', ['vLocale']);
		// init services, filters, directives
		vxSetupServices();
		vxSetupFilters();
		vxSetupDirectives();
	}

	/**
	 * @vxdoc interface
	 * @name vx.Module
	 * @description
	 *
	 * Interface for configuring vx {@link vx.module modules}.
	 */
	function moduler() {
		function ensure(obj, name, factory) {
			return obj[name] || (obj[name] = factory());
		}

		/** @type {Object.<string, vx.Module>} */
		var modules = {};
		/**
		 * @vxdoc function
		 * @name vx.module
		 * @description
		 *
		 * The `vx.module` is a global place for creating and registering VX modules. All
		 * modules (vx core or 3rd party) that should be available to an application must be
		 * registered using this mechanism.
		 *
		 *
		 * # Module
		 *
		 * A module is a collocation of services, directives, filters, and configuration information. Module
		 * is used to configure the {@link AUTO.$injector $injector}.
		 *
		 * <pre>
		 * // Create a new module
		 * var myModule = vx.module('myModule', []);
		 *
		 * // register a new service
		 * myModule.value('appName', 'MyCoolApp');
		 *
		 * // configure existing services inside initialization blocks.
		 * myModule.config(function($locationProvider) {
		 *   // Configure existing providers
		 *   $locationProvider.hashPrefix('!');
		 * });
		 * </pre>
		 *
		 * Then you can create an injector and load your modules like this:
		 *
		 * <pre>
		 * var injector = vx.injector(['v', 'MyModule'])
		 * </pre>
		 *
		 * However it's more likely that you'll just use
		 * {@link vx.directive:vApp vApp} or
		 * {@link vx.bootstrap} to simplify this process for you.
		 *
		 * @param {!string} name The name of the module to create or retrieve.
		 * @param {Array.<string>=} requires If specified then new module is being created. If unspecified then the
		 *        the module is being retrieved for further configuration.
		 * @param {Function} configFn Optional configuration function for the module. Same as
		 *        {@link vx.Module#config Module#config()}.
		 * @returns {module} new module with the {@link vx.Module} api.
		 */
		return function module(name, requires, configFn) {
			if (requires && modules.hasOwnProperty(name)) {
				modules[name] = null;
			}

			return ensure(modules, name, function() {
				if (!requires) {
					throw vError(21, "Module '{0}' is not available! You either misspelled the module name or forgot to load it.", name);
				}

				/** @type {!Array.<Array.<*>>} */
				var invokeQueue = [];
				/** @type {!Array.<Function>} */
				var runBlocks = [];
				var config = invokeLater('$injector', 'invoke');
				/** @type {vx.Module} */
				var moduleInstance = {
					// Private state
					_invokeQueue : invokeQueue,
					_runBlocks : runBlocks,

					/**
					 * @vxdoc property
					 * @name vx.Module#requires
					 * @propertyOf vx.Module
					 * @returns {Array.<string>} List of module names which must be loaded before this module.
					 * @description
					 * Holds the list of modules which the injector will load before the current module is loaded.
					 */
					requires : requires,

					/**
					 * @vxdoc property
					 * @name vx.Module#name
					 * @propertyOf vx.Module
					 * @returns {string} Name of the module.
					 * @description
					 */
					name : name,

					/**
					 * @vxdoc method
					 * @name vx.Module#provider
					 * @methodOf vx.Module
					 * @param {string} name service name
					 * @param {Function} providerType Construction function for creating new instance of the service.
					 * @description
					 * See {@link AUTO.$provide#provider $provide.provider()}.
					 */
					provider : invokeLater('$provide', 'provider'),

					/**
					 * @vxdoc method
					 * @name vx.Module#factory
					 * @methodOf vx.Module
					 * @param {string} name service name
					 * @param {Function} providerFunction Function for creating new instance of the service.
					 * @description
					 * See {@link AUTO.$provide#factory $provide.factory()}.
					 */
					factory : invokeLater('$provide', 'factory'),

					/**
					 * @vxdoc method
					 * @name vx.Module#service
					 * @methodOf vx.Module
					 * @param {string} name service name
					 * @param {Function} constructor A constructor function that will be instantiated.
					 * @description
					 * See {@link AUTO.$provide#service $provide.service()}.
					 */
					service : invokeLater('$provide', 'service'),

					/**
					 * @vxdoc method
					 * @name vx.Module#value
					 * @methodOf vx.Module
					 * @param {string} name service name
					 * @param {*} object Service instance object.
					 * @description
					 * See {@link AUTO.$provide#value $provide.value()}.
					 */
					value : invokeLater('$provide', 'value'),

					/**
					 * @vxdoc method
					 * @name vx.Module#constant
					 * @methodOf vx.Module
					 * @param {string} name constant name
					 * @param {*} object Constant value.
					 * @description
					 * Because the constant are fixed, they get applied before other provide methods.
					 * See {@link AUTO.$provide#constant $provide.constant()}.
					 */
					constant : invokeLater('$provide', 'constant', 'unshift'),

					/**
					 * @vxdoc method
					 * @name vx.Module#animation
					 * @methodOf vx.Module
					 * @param {string} name animation name
					 * @param {Function} animationFactory Factory function for creating new instance of an animation.
					 * @description
					 *
					 * Defines an animation hook that can be later used with {@link vx.directive:vAnimate vAnimate}
					 * alongside {@link vx.directive:vAnimate#Description common vx directives} as well as custom directives.
					 * <pre>
					 * module.animation('animation-name', function($inject1, $inject2) {
					 *   return {
					 *     //this gets called in preparation to setup an animation
					 *     setup : function(element) { ... },
					 *
					 *     //this gets called once the animation is run
					 *     start : function(element, done, memo) { ... }
					 *   }
					 * })
					 * </pre>
					 *
					 * See {@link vx.$animationProvider#register $animationProvider.register()} and
					 * {@link vx.directive:vAnimate vAnimate} for more information.
					 */
					animation : invokeLater('$animationProvider', 'register'),

					/**
					 * @vxdoc method
					 * @name vx.Module#filter
					 * @methodOf vx.Module
					 * @param {string} name Filter name.
					 * @param {Function} filterFactory Factory function for creating new instance of filter.
					 * @description
					 * See {@link vx.$filterProvider#register $filterProvider.register()}.
					 */
					filter : invokeLater('$filterProvider', 'register'),

					/**
					 * @vxdoc method
					 * @name vx.Module#controller
					 * @methodOf vx.Module
					 * @param {string} name Controller name.
					 * @param {Function} constructor Controller constructor function.
					 * @description
					 * See {@link vx.$controllerProvider#register $controllerProvider.register()}.
					 */
					controller : invokeLater('$controllerProvider', 'register'),

					/**
					 * @vxdoc method
					 * @name vx.Module#directive
					 * @methodOf vx.Module
					 * @param {string} name directive name
					 * @param {Function} directiveFactory Factory function for creating new instance of
					 * directives.
					 * @description
					 * See {@link vx.$compileProvider#directive $compileProvider.directive()}.
					 */
					directive : invokeLater('$compileProvider', 'directive'),

					/**
					 * @vxdoc method
					 * @name vx.Module#config
					 * @methodOf vx.Module
					 * @param {Function} configFn Execute this function on module load. Useful for service
					 *    configuration.
					 * @description
					 * Use this method to register work which needs to be performed on module loading.
					 */
					config : config,

					/**
					 * @vxdoc method
					 * @name vx.Module#run
					 * @methodOf vx.Module
					 * @param {Function} initializationFn Execute this function after injector creation.
					 *    Useful for application initialization.
					 * @description
					 * Use this method to register work which should be performed when the injector is done
					 * loading all modules.
					 */
					run : function(block) {
						runBlocks.push(block);
						return this;
					}
				};
				if (configFn) {
					config(configFn);
				}
				return moduleInstance;

				/**
				 * @param {string} provider
				 * @param {string} method
				 * @param {String=} insertMethod
				 * @returns {vx.Module}
				 */
				function invokeLater(provider, method, insertMethod) {
					return function() {
						invokeQueue[insertMethod || 'push']([provider, method, arguments]);
						return moduleInstance;
					};
				}

			});
		};
	}

	////////////////////////////////////
	//  vx initialization
	////////////////////////////////////

	/**
	 * @vxdoc directive
	 * @name vx.directive:vApp
	 *
	 * @element ANY
	 * @param {vx.Module} vApp an optional application
	 *   {@link vx.module module} name to load.
	 *
	 * @description
	 *
	 * Use this directive to auto-bootstrap an application. Only
	 * one directive can be used per HTML document. The directive
	 * designates the root of the application and is typically placed
	 * at the root of the page.
	 *
	 * In the example below if the `vApp` directive would not be placed
	 * on the `html` element then the document would not be compiled
	 * and the `{{ 1+2 }}` would not be resolved to `3`.
	 *
	 * `vApp` is the easiest way to bootstrap an application.
	 *
	 <doc:example>
	 <doc:source>
	 I can add: 1 + 2 =  {{ 1+2 }}
	 </doc:source>
	 </doc:example>
	 *
	 */
	function vxInit(element, bootstrap) {
		var elements = [element], appElement, module, names = ['v:app', 'v-app', 'x-v-app', 'data-v-app'], //
		V_APP_CLASS_REGEXP = /\sv[:\-]app(:\s*([\w\d_]+);?)?\s/;

		function append(element) {
			if (element)
				elements.push(element);
		}

		forEach(names, function(name) {
			names[name] = true;
			append(document.getElementById(name));
			name = name.replace(':', '\\:');
			forEach(jqLite(element).find('.' + name), append);
			forEach(jqLite(element).find('.' + name + '\\:'), append);
			forEach(jqLite(element).find('[' + name + ']'), append);
		});
		forEach(elements, function(element) {
			if (!appElement) {
				var className = ' ' + element.className + ' ';
				var match = V_APP_CLASS_REGEXP.exec(className);
				if (match) {
					appElement = element;
					module = (match[2] || '').replace(/\s+/g, ',');
				} else {
					forEach(element.attributes, function(attr) {
						if (attr.specified && !appElement && names[attr.name]) {
							appElement = element;
							module = attr.value;
						}
					});
				}
			}
		});
		if (appElement) {
			bootstrap(appElement, module ? [module] : []);
		}
	}

	/**
	 * @vxdoc function
	 * @name vx.bootstrap
	 * @description
	 * Use this function to manually start up vx application.
	 *
	 * See: {@link guide/bootstrap Bootstrap}
	 *
	 * @param {Element} element DOM element which is the root of vx application.
	 * @param {Array<String|Function>=} modules an array of module declarations. See: {@link vx.module modules}
	 * @returns {AUTO.$injector} Returns the newly created injector for this app.
	 */
	function bootstrap(element, modules) {
		var resumeBootstrapInternal = function() {
			modules = modules || [];
			modules.unshift(['$provide',
			function($provide) {
				$provide.value('$rootElement', jqLite(element));
			}]);
			modules.unshift('v');
			var injector = createInjector(modules);
			injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animator',
			function(scope, element, compile, injector, animator) {
				scope.$apply(function() {
					element.data('$injector', injector);
					compile(element)(scope);
				}, 'v-app');
				animator.enabled(true);
			}]);
			return injector;
		};

		var V_DEFER_BOOTSTRAP = /^V_DEFER_BOOTSTRAP!/;
		var defer = element.getAttributeNode('defer') !== null || (window && V_DEFER_BOOTSTRAP.test(window.name));

		if (!defer) {
			return resumeBootstrapInternal();
		}

		window.name = window.name.replace(V_DEFER_BOOTSTRAP, '');
		vx.resumeBootstrap = function(extraModules) {
			forEach(extraModules, function(module) {
				modules.push(module);
			});
			resumeBootstrapInternal();
		};
	}

	/**
	 * @vxdoc function
	 * @name vx.injector
	 * @function
	 *
	 * @description
	 * Creates an injector function that can be used for retrieving services as well as for
	 * dependency injection (see {@link guide/di dependency injection}).
	 *

	 * @param {Array.<string|Function>} modules A list of module functions or their aliases. See
	 *        {@link vx.module}. The `v` module must be explicitly added.
	 * @returns {function()} Injector function. See {@link AUTO.$injector $injector}.
	 *
	 * @example
	 * Typical usage
	 * <pre>
	 *   // create an injector
	 *   var $injector = vx.injector(['v']);
	 *
	 *   // use the injector to kick off your application
	 *   // use the type inference to auto inject arguments, or use implicit injection
	 *   $injector.invoke(function($rootScope, $compile, $document){
	 *     $compile($document)($rootScope);
	 *     $rootScope.$digest();
	 *   });
	 * </pre>
	 */

	/**
	 * @vxdoc object
	 * @name AUTO.$injector
	 * @function
	 *
	 * @description
	 *
	 * `$injector` is used to retrieve object instances as defined by
	 * {@link AUTO.$provide provider}, instantiate types, invoke methods,
	 * and load modules.
	 *
	 * The following always holds true:
	 *
	 * <pre>
	 *   var $injector = vx.injector();
	 *   expect($injector.get('$injector')).toBe($injector);
	 *   expect($injector.invoke(function($injector){
	 *     return $injector;
	 *   }).toBe($injector);
	 * </pre>
	 *
	 * # Injection Function Annotation
	 *
	 * JavaScript does not have annotations, and annotations are needed for dependency injection. The
	 * following are all valid ways of annotating function with injection arguments and are equivalent.
	 *
	 * <pre>
	 *   // inferred (only works if code not minified/obfuscated)
	 *   $injector.invoke(function(serviceA){});
	 *
	 *   // annotated
	 *   function explicit(serviceA) {};
	 *   explicit.$inject = ['serviceA'];
	 *   $injector.invoke(explicit);
	 *
	 *   // inline
	 *   $injector.invoke(['serviceA', function(serviceA){}]);
	 * </pre>
	 *
	 * ## Inference
	 *
	 * In JavaScript calling `toString()` on a function returns the function definition. The definition can then be
	 * parsed and the function arguments can be extracted. *NOTE:* This does not work with minification, and obfuscation
	 * tools since these tools change the argument names.
	 *
	 * ## `$inject` Annotation
	 * By adding a `$inject` property onto a function the injection parameters can be specified.
	 *
	 * ## Inline
	 * As an array of injection names, where the last item in the array is the function to call.
	 */
	function createInjector(modulesToLoad) {
		var INSTANTIATING = {}, providerSuffix = 'Provider', path = [], loadedModules = new HashMap(),
		//XXX provider space, providerInjector could access only by module's config(...)
		pending = [], providerCache = {
			/**
			 * @vxdoc object
			 * @name AUTO.$provide
			 *
			 * @description
			 *
			 * Use `$provide` to register new providers with the `$injector`. The providers are the factories for the instance.
			 * The providers share the same name as the instance they create with `Provider` suffixed to them.
			 *
			 * A provider is an object with a `$get()` method. The injector calls the `$get` method to create a new instance of
			 * a service. The Provider can have additional methods which would allow for configuration of the provider.
			 *
			 * <pre>
			 *   function GreetProvider() {
			 *     var salutation = 'Hello';
			 *
			 *     this.salutation = function(text) {
			 *       salutation = text;
			 *     };
			 *
			 *     this.$get = function() {
			 *       return function (name) {
			 *         return salutation + ' ' + name + '!';
			 *       };
			 *     };
			 *   }
			 *
			 *   describe('Greeter', function(){
			 *
			 *     beforeEach(module(function($provide) {
			 *       $provide.provider('greet', GreetProvider);
			 *     }));
			 *
			 *     it('should greet', inject(function(greet) {
			 *       expect(greet('vx')).toEqual('Hello vx!');
			 *     }));
			 *
			 *     it('should allow configuration of salutation', function() {
			 *       module(function(greetProvider) {
			 *         greetProvider.salutation('Ahoj');
			 *       });
			 *       inject(function(greet) {
			 *         expect(greet('vx')).toEqual('Ahoj vx!');
			 *       });
			 *     });
			 *
			 *   });
			 * </pre>
			 */
			$provide : {
				provider : supportObject(provider),
				factory : supportObject(factory),
				service : supportObject(service),
				value : supportObject(value),
				constant : supportObject(constant),
				decorator : decorator
			}
		}, providerInjector = (providerCache.$injector = createInternalInjector(providerCache, function() {
			throw vError(22, "Unknown provider: {0}", path.join(' <- '));
		})),
		//XXX instance space, instanceInjector could get by '$injector'
		instanceCache = {}, instanceInjector = (instanceCache.$injector = createInternalInjector(instanceCache, function(servicename) {
			var provider = providerInjector.get(servicename + providerSuffix);
			var instance = instanceInjector.invoke(provider.$get, provider);
			return instance;
		}));
		// XXX let provide know all Providers for trace
		providerCache.$provide.$providers = providerCache;

		forEach(loadModules(modulesToLoad), function(fn) {
			instanceInjector.invoke(fn || noop);
		});
		return instanceInjector;

		//****************************
		// $provider
		//***************************

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#provider
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * Register a provider for a service. The providers can be retrieved and can have additional configuration methods.
		 *
		 * @param {string} name The name of the instance. NOTE: the provider will be available under `name + 'Provider'` key.
		 * @param {(Object|function())} provider If the provider is:
		 *
		 *   - `Object`: then it should have a `$get` method. The `$get` method will be invoked using
		 *               {@link AUTO.$injector#invoke $injector.invoke()} when an instance needs to be created.
		 *   - `Constructor`: a new instance of the provider will be created using
		 *               {@link AUTO.$injector#instantiate $injector.instantiate()}, then treated as `object`.
		 *
		 * @returns {Object} registered provider instance
		 */

		function provider(name, provider_) {
			if (isFunction(provider_) || isArray(provider_)) {
				provider_ = providerInjector.instantiate(provider_);
			}
			if (!provider_.$get) {
				throw vError(23, "Provider '{0}' must define $get factory method.", name);
			}
			return providerCache[name + providerSuffix] = provider_;
		}

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#factory
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * A short hand for configuring services if only `$get` method is required.
		 *
		 * @param {string} name The name of the instance.
		 * @param {function()} $getFn The $getFn for the instance creation. Internally this is a short hand for
		 * `$provide.provider(name, {$get: $getFn})`.
		 * @returns {Object} registered provider instance
		 */
		function factory(name, factoryFn) {
			return provider(name, {
				$get : factoryFn
			});
		}

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#service
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * A short hand for registering service of given class.
		 *
		 * @param {string} name The name of the instance.
		 * @param {Function} constructor A class (constructor function) that will be instantiated.
		 * @returns {Object} registered provider instance
		 */
		function service(name, constructor) {
			return factory(name, ['$injector',
			function($injector) {
				return $injector.instantiate(constructor);
			}]);

		}

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#value
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * A short hand for configuring services if the `$get` method is a constant.
		 *
		 * @param {string} name The name of the instance.
		 * @param {*} value The value.
		 * @returns {Object} registered provider instance
		 */
		function value(name, val) {
			return factory(name, valueFn(val));
		}

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#constant
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * A constant value, but unlike {@link AUTO.$provide#value value} it can be injected
		 * into configuration function (other modules) and it is not interceptable by
		 * {@link AUTO.$provide#decorator decorator}.
		 *
		 * @param {string} name The name of the constant.
		 * @param {*} value The constant value.
		 * @returns {Object} registered instance
		 */
		function constant(name, value) {
			providerCache[name] = value;
			instanceCache[name] = value;
		}

		/**
		 * @vxdoc method
		 * @name AUTO.$provide#decorator
		 * @methodOf AUTO.$provide
		 * @description
		 *
		 * Decoration of service, allows the decorator to intercept the service instance creation. The
		 * returned instance may be the original instance, or a new instance which delegates to the
		 * original instance.
		 *
		 * @param {string} name The name of the service to decorate.
		 * @param {function()} decorator This function will be invoked when the service needs to be
		 *    instantiated. The function is called using the {@link AUTO.$injector#invoke
		 *    injector.invoke} method and is therefore fully injectable. Local injection arguments:
		 *
		 *    * `$delegate` - The original service instance, which can be monkey patched, configured,
		 *      decorated or delegated to.
		 */
		function decorator(serviceName, decorFn) {
			var origProvider = providerInjector.get(serviceName + providerSuffix), orig$get = origProvider.$get;
			origProvider.$get = function() {
				var origInstance = instanceInjector.invoke(orig$get, origProvider);
				return instanceInjector.invoke(decorFn, null, {
					$delegate : origInstance
				});
			};
		}

		//***************************
		// Module Loading
		//***************************
		function loadModules(modulesToLoad) {
			var runBlocks = [];
			forEach(modulesToLoad, function(module) {
				if (loadedModules.get(module))
					return;
				loadedModules.put(module, true);
				if (isString(module)) {
					var moduleFn = vx.module(module);
					runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
					try {
						for (var invokeQueue = moduleFn._invokeQueue, i = 0, ii = invokeQueue.length; i < ii; i++) {
							var invokeArgs = invokeQueue[i], provider = providerInjector.get(invokeArgs[0]);
							provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
						}
					} catch (e) {
						if (e.message)
							e.message += ' from ' + module + ', args: ' + toJson(invokeArgs);
						throw e;
					}
				} else if (isFunction(module)) {
					try {
						runBlocks.push(providerInjector.invoke(module));
					} catch (e) {
						if (e.message)
							e.message += ' from ' + module;
						throw e;
					}
				} else if (isArray(module)) {
					try {
						runBlocks.push(providerInjector.invoke(module));
					} catch (e) {
						if (e.message)
							e.message += ' from ' + String(module[module.length - 1]);
						throw e;
					}
				} else {
					assertArgFn(module, 'module');
				}
			});
			return runBlocks;
		}

		//**************************
		// internal Injector
		//**************************

		function createInternalInjector(cache, factory) {

			/**
			 * @vxdoc method
			 * @name AUTO.$injector#annotate
			 * @methodOf AUTO.$injector
			 *
			 * @description
			 * Returns an array of service names which the function is requesting for injection. This API is used by the injector
			 * to determine which services need to be injected into the function when the function is invoked. There are three
			 * ways in which the function can be annotated with the needed dependencies.
			 *
			 * # Argument names
			 *
			 * The simplest form is to extract the dependencies from the arguments of the function. This is done by converting
			 * the function into a string using `toString()` method and extracting the argument names.
			 * <pre>
			 *   // Given
			 *   function MyController($scope, $route) {
			 *     // ...
			 *   }
			 *
			 *   // Then
			 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
			 * </pre>
			 *
			 * This method does not work with code minfication / obfuscation. For this reason the following annotation strategies
			 * are supported.
			 *
			 * # The `$inject` property
			 *
			 * If a function has an `$inject` property and its value is an array of strings, then the strings represent names of
			 * services to be injected into the function.
			 * <pre>
			 *   // Given
			 *   var MyController = function(obfuscatedScope, obfuscatedRoute) {
			 *     // ...
			 *   }
			 *   // Define function dependencies
			 *   MyController.$inject = ['$scope', '$route'];
			 *
			 *   // Then
			 *   expect(injector.annotate(MyController)).toEqual(['$scope', '$route']);
			 * </pre>
			 *
			 * # The array notation
			 *
			 * It is often desirable to inline Injected functions and that's when setting the `$inject` property is very
			 * inconvenient. In these situations using the array notation to specify the dependencies in a way that survives
			 * minification is a better choice:
			 *
			 * <pre>
			 *   // We wish to write this (not minification / obfuscation safe)
			 *   injector.invoke(function($compile, $rootScope) {
			 *     // ...
			 *   });
			 *
			 *   // We are forced to write break inlining
			 *   var tmpFn = function(obfuscatedCompile, obfuscatedRootScope) {
			 *     // ...
			 *   };
			 *   tmpFn.$inject = ['$compile', '$rootScope'];
			 *   injector.invoke(tmpFn);
			 *
			 *   // To better support inline function the inline annotation is supported
			 *   injector.invoke(['$compile', '$rootScope', function(obfCompile, obfRootScope) {
			 *     // ...
			 *   }]);
			 *
			 *   // Therefore
			 *   expect(injector.annotate(
			 *      ['$compile', '$rootScope', function(obfus_$compile, obfus_$rootScope) {}])
			 *    ).toEqual(['$compile', '$rootScope']);
			 * </pre>
			 *
			 * @param {function|Array.<string|Function>} fn Function for which dependent service names need to be retrieved as described
			 *   above.
			 *
			 * @returns {Array.<string>} The names of the services which the function requires.
			 */
			var FN_ARGS = /^function\s*[^\(]*\(\s*([^\)]*)\)/m;
			var FN_ARG_SPLIT = /,/;
			var FN_ARG = /^\s*(_?)(\S+?)\1\s*$/;
			var STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;

			function annotate(fn) {
				var $inject, fnText, argDecl, last;

				if ( typeof fn == 'function') {
					if (!( $inject = fn.$inject)) {
						$inject = [];
						fnText = fn.toString().replace(STRIP_COMMENTS, '');
						argDecl = fnText.match(FN_ARGS);
						forEach(argDecl[1].split(FN_ARG_SPLIT), function(arg) {
							arg.replace(FN_ARG, function(all, underscore, name) {
								$inject.push(name);
							});
						});
						fn.$inject = $inject;
					}
				} else if (isArray(fn)) {
					last = fn.length - 1;
					assertArgFn(fn[last], 'fn');
					$inject = fn.slice(0, last);
				} else {
					assertArgFn(fn, 'fn', true);
				}
				return $inject;
			}

			/**
			 * @vxdoc method
			 * @name AUTO.$injector#get
			 * @methodOf AUTO.$injector
			 *
			 * @description
			 * Return an instance of the service.
			 *
			 * @param {string} name The name of the instance to retrieve.
			 * @return {*} The instance.
			 */
			function getService(serviceName) {
				if (cache.hasOwnProperty(serviceName)) {
					if (cache[serviceName] === INSTANTIATING) {
						throw vError(24, 'Circular dependency found: {0}', path.join(' <- '));
					}
					return cache[serviceName];
				} else {
					try {
						path.unshift(serviceName);
						cache[serviceName] = INSTANTIATING;
						return cache[serviceName] = factory(serviceName);
					} finally {
						path.shift();
						if (path.length === 0 && pending.length > 0) {
							// when root service, fire all post Construct
							while (pending.length > 0) {
								var fn = pending.shift();
								fn();
							}
						}
					}
				}
			}

			/**
			 * @vxdoc method
			 * @name AUTO.$injector#invoke
			 * @methodOf AUTO.$injector
			 *
			 * @description
			 * Invoke the method and supply the method arguments from the `$injector`.
			 *
			 * @param {!function} fn The function to invoke. The function arguments come form the function annotation.
			 * @param {Object=} self The `this` for the invoked method.
			 * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
			 *   the `$injector` is consulted.
			 * @returns {*} the value returned by the invoked `fn` function.
			 */
			function invoke(fn, self, locals) {
				var args = [], $inject = annotate(fn), length, i, key;
				var $remote, $http;

				for ( i = 0, length = $inject.length; i < length; i++) {
					key = $inject[i];
					if ( typeof key !== 'string') {
						throw vError(25, 'Incorrect injection token! Expected service name as string, got {0}', key);
					}
					if (locals && locals.$element && (key === '$remote' || key === '$http')) {
						if (!$remote) {
							var $$remote = getService('$$remote');
							injectRemote(locals.$element, locals, '$remote.', false, $$remote);
							$remote = locals.$remote;
							$http = $remote.$http();
						}
						args.push(key === '$http' ? $http : $remote);
					} else
						args.push(locals && locals.hasOwnProperty(key) ? locals[key] : getService(key));
				}
				if (!fn.$inject) {
					// this means that we must be an array.
					fn = fn[length];
				}
				return _fastInvoke(fn, self, args);
			}

			/**
			 * @vxdoc method
			 * @name AUTO.$injector#instantiate
			 * @methodOf AUTO.$injector
			 * @description
			 * Create a new instance of JS type. The method takes a constructor function invokes the new operator and supplies
			 * all of the arguments to the constructor function as specified by the constructor annotation.
			 *
			 * @param {function} Type Annotated constructor function.
			 * @param {Object=} locals Optional object. If preset then any argument names are read from this object first, before
			 *   the `$injector` is consulted.
			 * @returns {Object} new instance of `Type`.
			 */
			function instantiate(Type, locals) {
				var Constructor = function() {
				}, instance, returnedValue;

				// Check if Type is annotated and use just the given function at n-1 as parameter
				// e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
				Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
				instance = new Constructor();
				returnedValue = invoke(Type, instance, locals);
				return isObject(returnedValue) ? returnedValue : instance;
			}

			/**
			 * @vxdoc method
			 * @name AUTO.$injector#has
			 * @methodOf AUTO.$injector
			 *
			 * @description
			 * Allows the user to query if the particular service exist.
			 *
			 * @param {string} Name of the service to query.
			 * @returns {boolean} returns true if injector has given service.
			 */
			function has(name) {
				return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
			}

			return {
				invoke : invoke,
				instantiate : instantiate,
				get : getService,
				annotate : annotate,
				has : has,
				$cache : cache
			};
		}

	}

	var IE_GC = vx.IE_GC = noop;

	vxSetup(vx);
	jqLite(document).ready(function() {
		vxInit(document, bootstrap);
		if (msie) {
			var gcDiv = jqLite('<div id="IE_GC_BIN" style="display:none;" />')[0];
			jqLite(document).find('body').append(gcDiv);
			IE_GC = vx.IE_GC = function(el) {
				gcDiv.appendChild(el);
				gcDiv.innerHTML = '';
			};
		}
	});
})(window, document, window.$);

//vx.element(document).find('head').append('<style type="text/css">@charset "UTF-8";[v\\:cloak],[v-cloak],[data-v-cloak],[x-v-cloak],.v-cloak,.x-v-cloak{display:none;}v\\:form{display:block;}</style>');
